"""
Coordinator服务器 - 接收来自Controller的实例变化事件
支持ADD、DEL、SET三种事件类型，并提供liveness和heartbeat接口
"""

import json
import threading
from typing import Dict, List, Optional
from datetime import datetime, timezone

from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field

from motor.resources.http_msg_spec import InsEventMsg, EventType
from motor.resources.instance import Instance
from motor.coordinator.metrics.metrics_listener import MetricsListener
from motor.utils.logger import get_logger

logger = get_logger(__name__)

# 全局状态存储
class CoordinatorState:
    def __init__(self):
        self.instances: Dict[str, Instance] = {}
        self.last_heartbeat: Optional[datetime] = None
        self.event_history: List[Dict] = []
        self._lock = threading.Lock()
    
    def add_instance(self, instance: Instance) -> None:
        """添加实例"""
        with self._lock:
            self.instances[instance.job_name] = instance
            self.event_history.append({
                "timestamp": datetime.now(timezone.utc).isoformat(),
                "event": "ADD",
                "job_name": instance.job_name,
                "instance": instance.model_dump()
            })
            logger.info(f"Instance added: {instance.job_name}")
    
    def remove_instance(self, job_name: str) -> None:
        """删除实例"""
        with self._lock:
            if job_name in self.instances:
                instance = self.instances.pop(job_name)
                self.event_history.append({
                    "timestamp": datetime.now(timezone.utc).isoformat(),
                    "event": "DEL",
                    "job_name": job_name,
                    "instance": instance.model_dump()
                })
                logger.info(f"Instance removed: {job_name}")
            else:
                logger.warning(f"Instance not found for removal: {job_name}")
    
    def set_instances(self, instances: List[Instance]) -> None:
        """设置实例列表（全量更新）"""
        with self._lock:
            old_instances = self.instances.copy()
            self.instances.clear()
            
            for instance in instances:
                self.instances[instance.job_name] = instance
            
            self.event_history.append({
                "timestamp": datetime.now(timezone.utc).isoformat(),
                "event": "SET",
                "old_count": len(old_instances),
                "new_count": len(instances),
                "instances": [inst.model_dump() for inst in instances]
            })
            logger.info(f"Instances set: {len(old_instances)} -> {len(instances)}")
    
    def update_heartbeat(self) -> None:
        """更新心跳时间"""
        with self._lock:
            self.last_heartbeat = datetime.now(timezone.utc)
    
    def get_status(self) -> Dict:
        """获取当前状态"""
        with self._lock:
            return {
                "instance_count": len(self.instances),
                "instances": {name: inst.model_dump() for name, inst in self.instances.items()},
                "last_heartbeat": self.last_heartbeat.isoformat() if self.last_heartbeat else None,
                "event_count": len(self.event_history)
            }

# 全局状态实例
coordinator_state = CoordinatorState()

# FastAPI应用
app = FastAPI(
    title="Motor Coordinator Server",
    description="接收Controller发送的实例变化事件",
    version="1.0.0"
)

# 请求/响应模型
class HeartbeatRequest(BaseModel):
    status: str = Field(..., description="心跳状态")

class HeartbeatResponse(BaseModel):
    status: str = Field(..., description="响应状态")
    timestamp: str = Field(..., description="时间戳")

class LivenessResponse(BaseModel):
    status: str = Field(..., description="服务状态")
    instance_count: int = Field(..., description="当前实例数量")
    last_heartbeat: Optional[str] = Field(..., description="最后心跳时间")
    uptime: str = Field(..., description="运行时间")

class StatusResponse(BaseModel):
    coordinator_status: Dict = Field(..., description="协调器状态")
    event_history: List[Dict] = Field(..., description="事件历史")

@app.post("/coordinator/active")
async def handle_instance_events(request: Request):
    """
    处理实例变化事件
    支持ADD、DEL、SET三种事件类型
    """
    try:
        # 解析请求体
        body = await request.json()
        event_msg = InsEventMsg(**body)
        
        logger.info(f"Received event: {event_msg.event} with {len(event_msg.instances)} instances")
        
        # 根据事件类型处理
        if event_msg.event == EventType.ADD:
            for instance in event_msg.instances:
                coordinator_state.add_instance(instance)
            message = f"Successfully processed {len(event_msg.instances)} ADD events"
            
        elif event_msg.event == EventType.DEL:
            for instance in event_msg.instances:
                coordinator_state.remove_instance(instance.job_name)
            message = f"Successfully processed {len(event_msg.instances)} DEL events"
            
        elif event_msg.event == EventType.SET:
            coordinator_state.set_instances(event_msg.instances)
            message = f"Successfully processed SET event with {len(event_msg.instances)} instances"
            
        else:
            raise HTTPException(status_code=400, detail=f"Unknown event type: {event_msg.event}")
        
        return JSONResponse(
            status_code=200,
            content={
                "status": "success",
                "message": message,
                "event_type": event_msg.event,
                "instance_count": len(event_msg.instances)
            }
        )
        
    except Exception as e:
        logger.error(f"Error processing instance events: {e}")
        raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")

@app.post("/coordinator/heartbeat", response_model=HeartbeatResponse)
async def handle_heartbeat(heartbeat: HeartbeatRequest):
    """
    处理心跳检测
    """
    try:
        coordinator_state.update_heartbeat()
        logger.debug(f"Heartbeat received: {heartbeat.status}")
        
        return HeartbeatResponse(
            status="alive",
            timestamp=datetime.now(timezone.utc).isoformat()
        )
        
    except Exception as e:
        logger.error(f"Error processing heartbeat: {e}")
        raise HTTPException(status_code=500, detail=f"Heartbeat error: {str(e)}")

@app.get("/liveness", response_model=LivenessResponse)
async def liveness_check():
    """
    健康检查接口
    检查服务是否正常运行
    """
    try:
        status = coordinator_state.get_status()
        
        # 检查心跳是否正常（5秒内有心跳认为正常）
        is_healthy = True
        if status["last_heartbeat"]:
            last_hb = datetime.fromisoformat(status["last_heartbeat"])
            time_diff = (datetime.now(timezone.utc) - last_hb).total_seconds()
            if time_diff > 5:
                is_healthy = False
        
        return LivenessResponse(
            status="healthy" if is_healthy else "unhealthy",
            instance_count=status["instance_count"],
            last_heartbeat=status["last_heartbeat"],
            uptime="running"
        )
        
    except Exception as e:
        logger.error(f"Error in liveness check: {e}")
        return LivenessResponse(
            status="error",
            instance_count=0,
            last_heartbeat=None,
            uptime="error"
        )

@app.get("/status", response_model=StatusResponse)
async def get_status():
    """
    获取协调器完整状态
    """
    try:
        status = coordinator_state.get_status()
        return StatusResponse(
            coordinator_status=status,
            event_history=coordinator_state.event_history[-10:]  # 返回最近10个事件
        )
        
    except Exception as e:
        logger.error(f"Error getting status: {e}")
        raise HTTPException(status_code=500, detail=f"Status error: {str(e)}")

@app.get("/instances")
async def get_instances():
    """
    获取当前所有实例
    """
    try:
        status = coordinator_state.get_status()
        return {
            "instances": status["instances"],
            "count": status["instance_count"]
        }
        
    except Exception as e:
        logger.error(f"Error getting instances: {e}")
        raise HTTPException(status_code=500, detail=f"Instances error: {str(e)}")

metric_listener = MetricsListener()
@app.get("/metrics")
async def get_metrics():
    """
    获取metrics指标
    """
    try:
        return {
            "metrics": metric_listener.prometheus_metrics_handler()
        }
        
    except Exception as e:
        logger.error(f"Error getting metrics: {e}")
        raise HTTPException(status_code=500, detail=f"Instances error: {str(e)}")

@app.get("/instance/metrics")
async def get_metrics():
    """
    获取metrics指标
    """
    try:
        return {
            "metrics": metric_listener.prometheus_instance_metrics_handler()
        }

    except Exception as e:
        logger.error(f"Error getting instance metrics: {e}")
        raise HTTPException(status_code=500, detail=f"Instances error: {str(e)}")

@app.get("/")
async def root():
    """
    根路径，返回API信息
    """
    return {
        "service": "Motor Coordinator Server",
        "version": "1.0.0",
        "endpoints": {
            "POST /coordinator/active": "处理实例变化事件",
            "POST /coordinator/heartbeat": "心跳检测",
            "GET /liveness": "健康检查",
            "GET /status": "获取完整状态",
            "GET /instances": "获取实例列表"
        }
    }

def main():
    """主函数 - 启动Coordinator服务器"""
    import uvicorn
    
    logger.info("Starting Motor Coordinator Server...")
    uvicorn.run(
        app,
        host="0.0.0.0",
        port=9999,
        log_level="info"
    )

if __name__ == "__main__":
    main()
